/** @file    DiscoveryUdpMessage.cpp
 *  @author  Alessandro Polo
 *  @version $Id: DiscoveryUdpMessage.cpp 2581 2010-05-27 15:08:17Z alex $
 *  @brief
 * File containing methods for the wosh::DiscoveryUdpMessage class.
 * The header for this class can be found in DiscoveryUdpMessage.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include "DiscoveryUdpMessage.h"

 #include <core/Utilities.h>
 #include <string.h>


using namespace std;
namespace wosh {

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void DiscoveryUdpMessage::clear()
 {
	memset( (char*)&this->dd_data, '\0', sizeof(this->dd_data) );

	this->dd_data.protocol_version = _DiscoveryUdpMessage_ProtocolVersion;
	this->dd_data.kernel_type = 0;
	this->dd_data.kernel_state = 0;
	this->dd_data.notifyFreq = 0;

	memset( this->dd_data.kernel_name, '\0', _DiscoveryUdpMessage_KernelName_MAXSIZE );
	memset( this->dd_data.bind_address, '\0', _DiscoveryUdpMessage_BindAddress_MAXSIZE );

	this->supportedProtocols = "";
	this->neighbours = "";
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////// SERIALIZATION

int DiscoveryUdpMessage::saveTo( char* data, int maxSize )
 {
	if ( data == NULL) return -1;
	if ( maxSize == -1 ) maxSize = DiscoveryUdpMessage::MaxLength;

	if ( maxSize < (int)sizeof(this->dd_data) )
		return -1;

	int len = sizeof(this->dd_data);
	memcpy( data, &this->dd_data, len );

	int spLen = this->supportedProtocols.size();
	if ( maxSize < len + spLen )
		return -1;
	memcpy( data+len, &spLen, sizeof(int) );
	len += sizeof(int);
	memcpy( data+len, this->supportedProtocols.c_str(), this->supportedProtocols.size() );
	len += this->supportedProtocols.size();

	int nbLen = this->neighbours.size();
	if ( maxSize < len + nbLen )
		return -1;
	memcpy( data+len, &nbLen, sizeof(int) );
	len += sizeof(int);
	memcpy( data+len, this->neighbours.c_str(), this->neighbours.size() );
	len += this->neighbours.size();

	return len;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////// DE-SERIALIZATION

WRESULT DiscoveryUdpMessage::loadFrom( const char* data, int maxSize )
 {
	if ( maxSize < (int)sizeof(this->dd_data) )
		return WRET_ERR_PARAM;

	if ( data[0] != _DiscoveryUdpMessage_ProtocolVersion )
		return WRET_ERR_ILLEGAL_USE;

	int cPos = 0;
	memcpy( &this->dd_data, data, sizeof(this->dd_data) );
	cPos += sizeof(this->dd_data);

	if ( maxSize <= cPos )
		return WRET_ERR_PARAM;

	int spLen = 0;
	memcpy( &spLen, data+cPos, sizeof(int) );
	cPos += sizeof(int);
	if ( spLen > 0 ) {
		this->supportedProtocols.assign(data+cPos, spLen);
		Utilities::trimSpaces(this->supportedProtocols);
		Utilities::trimEndLine(this->supportedProtocols);
	 }
	cPos += spLen;

	if ( maxSize <= cPos )
		return WRET_ERR_PARAM;

	int nbLen = 0;
	memcpy( &nbLen, data+cPos, sizeof(int) );
	cPos += sizeof(int);
	if ( nbLen > 0 ) {
		this->neighbours.assign(data+cPos, nbLen);
		Utilities::trimSpaces(this->neighbours);
		Utilities::trimEndLine(this->neighbours);
	 }
	cPos += nbLen;

	return WRET_OK;
}

//////////////////////////////////////////////////////////////////////////////////////////// DE-SERIALIZATION
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////// SETTERS

bool DiscoveryUdpMessage::setKernelName( const string& value )
 {
	if ( value.size() > _DiscoveryUdpMessage_KernelName_MAXSIZE )
		return false;

	memset( this->dd_data.kernel_name, '\0', _DiscoveryUdpMessage_KernelName_MAXSIZE );
	strcpy( this->dd_data.kernel_name, value.c_str() );
	return true;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool DiscoveryUdpMessage::setDiscoveryBindAddress( const string& value )
 {
	if ( value.size() > _DiscoveryUdpMessage_BindAddress_MAXSIZE )
		return false;

	memset( this->dd_data.bind_address, '\0', _DiscoveryUdpMessage_BindAddress_MAXSIZE );
	strcpy( this->dd_data.bind_address, value.c_str() );
	return true;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void DiscoveryUdpMessage::setSupportedProtocols( const std::vector<std::string>& protocols ) {
	this->supportedProtocols = Utilities::joinVector( protocols, ";" );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void DiscoveryUdpMessage::setNeighbours( const std::map<std::string, long>& neighb )
 {
	this->neighbours = "";
	std::map<std::string, long>::const_iterator itp;
	for ( itp=neighb.begin(); itp!=neighb.end(); itp++ ) {
		this->neighbours += Utilities::format("%s:%ld;", itp->first.c_str(), itp->second);
	 }
 }

///////////////////////////////////////////////////////////////////////////////////////////////////// SETTERS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////// GETTERS

int DiscoveryUdpMessage::getSupportedProtocols( std::vector<std::string>& protocols ) const {
	return Utilities::splitString(this->supportedProtocols, ";", protocols, false, true);
 }

int DiscoveryUdpMessage::getNeighbours( std::map<std::string, long>& neighb ) const
 {
	vector<std::string> items;
	Utilities::splitString(this->neighbours, ";", items, false, true);
	std::vector<std::string>::const_iterator itp;
	for ( itp=items.begin(); itp!=items.end(); itp++ ) {
		vector<std::string> fields;
		if ( Utilities::splitString(*itp, ":", fields, false, true) != 2 ) continue;
		neighb[fields.at(0)] = Utilities::fromString<long>(fields.at(1));
	 }
	return neighb.size();
 }

///////////////////////////////////////////////////////////////////////////////////////////////////// GETTERS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

};
